package com.jichaoyun.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jichaoyun.common.enums.MyExceptiontType;
import com.jichaoyun.dao.mapper.StationInfoMapper;
import com.jichaoyun.model.entity.StationInfo;
//import com.jichaoyun.common.enums.MyExceptiontType;
import com.jichaoyun.common.ex.MyException;
//import com.jichaoyun.dao.mapper.StationInfoMapper;
import com.jichaoyun.service.ComPortService;
//import com.jichaoyun.util.ComUtils.SerialPortUtil;
import com.jichaoyun.service.util.ComUtils.SerialPortUtil;
import gnu.io.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class ComPortServiceImpl implements ComPortService {

    @Autowired
    private StationInfoMapper stationInfoMapper;

    public static Map<String,SerialPort> serialPortMap = new HashMap<>();

    public static Map<Integer,String> ComMap = new HashMap<>();

    public static Map<SerialPort,Boolean> comReceiveMap = new HashMap<>();

    public static Map<SerialPort,Integer> comStateMap = new HashMap<>();

    public static Map<SerialPort,Float> rechargeMap = new HashMap<>();

    public static Map<SerialPort,byte[]> ICCardMap = new HashMap<>();

    @Override
    public ArrayList<String> findPort() {
        //获得当前所有可用串口
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();

        ArrayList<String> portNameList = new ArrayList<>();

        //将可用串口名添加到List并返回该List
        while (portList.hasMoreElements()) {
            String portName = portList.nextElement().getName();
            portNameList.add(portName);
        }

        return portNameList;
    }

    @Override
    public SerialPort openPort(Integer userId, String portName, int baudrate, int databits, int parity, int stopbits) {
        try {
            //通过端口名识别端口
            CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);

            //打开端口，并给端口名字和一个timeout（打开操作的超时时间）
            CommPort commPort = portIdentifier.open(portName, 2000);

            //判断是不是串口
            if (commPort instanceof SerialPort) {

                SerialPort serialPort = (SerialPort) commPort;
                try {
                    //设置一下串口的波特率等参数
                    serialPort.setSerialPortParams(baudrate, databits, stopbits, parity);
                    ComMap.put(userId,portName);
                    serialPortMap.put(portName,serialPort);
                } catch (UnsupportedCommOperationException e) {
//                    throw new SerialPortParameterFailure();
                }

                System.out.println("Open " + portName + " sucessfully !");
                return serialPort;
            } else {
                //不是串口
                throw new MyException(MyExceptiontType.ISNOTPORTERROR,"不是串口");
            }
        } catch (NoSuchPortException e1) {
            throw new MyException(MyExceptiontType.NOTPORTFOUNDERROR,"没有找到端口");

        } catch (PortInUseException e2) {
            throw new MyException(MyExceptiontType.PORTUSEDERROR,"端口被占用");

        }
    }

    @Override
    public String ConnectCardRead(Integer userId) throws InterruptedException {
        String port = ComMap.get(userId);
        SerialPortUtil serialPortUtil = new SerialPortUtil();
        SerialPort serialPort = serialPortMap.get(port);
        serialPortUtil.connectCardReader(serialPort);

        Thread.sleep(1000);

        if (Objects.equals(readPort(serialPort), "读卡器连接成功")){
            return "读卡器连接成功";
        }else {
            throw new MyException(MyExceptiontType.ICCARDCONNECTERROR,"连接失败");
        }
    }

    @Override
    public String readPort(SerialPort serialPort) throws InterruptedException {

        SerialPortUtil serialPortUtil = new SerialPortUtil();

        return serialPortUtil.serialPort_DataReceived(serialPort);
    }

    @Override
    public String readCardNum(Integer userId) throws InterruptedException {
        String port = ComMap.get(userId);
        SerialPort serialPort = serialPortMap.get(port);
        SerialPortUtil serialPortUtil = new SerialPortUtil();
        serialPortUtil.readCardNum(serialPort);

        Thread.sleep(500);
        readPort(serialPort);
        Thread.sleep(500);

        String res = readPort(serialPort);
        if (res.startsWith("卡号为")){
            return res;
        }else {
            throw new MyException(MyExceptiontType.ICCARDNUMREADERROR,"读取卡号失败");
        }
    }

    @Override
    public void closePort(Integer userId) {
        String port = ComMap.get(userId);
        SerialPort serialPort = serialPortMap.get(port);
        SerialPortUtil serialPortUtil = new SerialPortUtil();
        serialPortUtil.closePort(serialPort);
        serialPortMap.remove(port);
        ComMap.remove(userId);
    }

    @Override
    public List<String> findNoICStation() {

        LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.isNull(StationInfo::getIcCardNum)
                .eq(StationInfo::getIsLeaf,1);
        List<StationInfo> stationInfoList = this.stationInfoMapper.selectList(lambdaQueryWrapper);

        List<String> res = new ArrayList<>();
        for(StationInfo stationInfo:stationInfoList){
            res.add(stationInfo.getStationName());
        }
        return res;
    }

    @Override
    public List<String> findHadICStation() {

        LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.isNotNull(StationInfo::getIcCardNum)
                .eq(StationInfo::getIsLeaf,1);
        List<StationInfo> stationInfoList = this.stationInfoMapper.selectList(lambdaQueryWrapper);

        List<String> res = new ArrayList<>();
        for(StationInfo stationInfo:stationInfoList){
            res.add(stationInfo.getStationName());
        }
        return res;
    }


    @Override
    public void bindingIcCard(String stationName, String ICCardNum) {
        LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StationInfo::getIcCardNum,ICCardNum);
        StationInfo stationInfo = this.stationInfoMapper.selectOne(lambdaQueryWrapper);

        if(stationInfo != null){
            throw new MyException(MyExceptiontType.ICCARDBOUNDERROR,"该IC卡已被其他站点绑定");
        }else {
            LambdaQueryWrapper<StationInfo> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
            lambdaQueryWrapper1.eq(StationInfo::getStationName,stationName);
            StationInfo stationInfo1 = this.stationInfoMapper.selectOne(lambdaQueryWrapper1);

            if(stationInfo1.getIcCardNum() != null){
                throw new MyException(MyExceptiontType.STATIONICCARDBINDERROR,"该站点已绑定IC卡");
            }else {
                stationInfo1.setIcCardNum(ICCardNum);
                this.stationInfoMapper.updateById(stationInfo1);
            }
        }
    }

    @Override
    public void bindingBoundIcCard(String ICCardNum) {
        LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StationInfo::getIcCardNum,ICCardNum);
        StationInfo stationInfo = this.stationInfoMapper.selectOne(lambdaQueryWrapper);

        if(stationInfo == null){
            throw new MyException(MyExceptiontType.STATIONICCARDNOTBINDERROR,null);
        }
        stationInfo.setIcCardNum(ICCardNum);
        this.stationInfoMapper.updateById(stationInfo);
    }

    @Override
    public String getStationNameByIcCard(String ICCardNum) {
        LambdaQueryWrapper<StationInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StationInfo::getIcCardNum,ICCardNum);
        StationInfo stationInfo = this.stationInfoMapper.selectOne(lambdaQueryWrapper);
        if(stationInfo == null){
            throw new MyException(MyExceptiontType.ICCARDBINDERROR,"该IC卡未绑定");
        }else {
            return stationInfo.getStationName();
        }
    }



    @Override
    public String reChargeIcCard(Integer userId,Float number) throws InterruptedException {
        String port = ComMap.get(userId);
        SerialPort serialPort = serialPortMap.get(port);
        SerialPortUtil serialPortUtil = new SerialPortUtil();

        rechargeMap.put(serialPort,number);
        //发送开始充值命令
        serialPortUtil.reChargeIcCard(serialPort,number);

        //读取开始命令的返回值并发送密钥验证命令
        readPort(serialPort);

        //读取密钥验证结果并发送读卡命令
        if(Objects.equals(readPort(serialPort), "密钥验证失败")){
            throw new MyException(MyExceptiontType.ICCARDKEYERROR,null);
        }

        //读取读卡命令返回结果并发送写卡命令
        if(Objects.equals(readPort(serialPort), "读取IC卡失败")){
            throw new MyException(MyExceptiontType.ICCARDREADERROR,null);
        }

        //返回写卡结果
        return readPort(serialPort);
    }
}


